﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Silverlight.Testing;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SilverTile.Xaml;
using System.Linq;
using System.Collections.Generic;
using SilverTile;
using System.Windows.Markup;
using SilverTile.Sprites;

namespace SilverTileTests
{
    [TestClass]
    public class XamlSpriteAnimationTests
    {


        private string _xaml =
            @"
            <UserControl
                xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
                xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""
                         xmlns:st=""clr-namespace:SilverTile.Xaml;assembly=SilverTile"">

                <UserControl.Resources>
                    <st:SpriteAnimation x:Key=""Player"" Fps=""20"">
                        <st:FrameAnimation Name=""Left"">
                                <st:SpriteFrame Source=""/SilverTileTests;component/Tiles/0002.png"" />
                                <st:SpriteFrame Source=""/SilverTileTests;component/Tiles/0002.png"" />
                        </st:FrameAnimation>
                    </st:SpriteAnimation>
                </UserControl.Resources>

            </UserControl>
            ";

        [TestMethod]
        public void SpriteAnimation_Should_Have_X_And_Y_Properties()
        {

            SpriteAnimation anim = new SpriteAnimation();
            anim.SetValue(SpriteAnimation.XProperty, 10);
            anim.SetValue(SpriteAnimation.YProperty, 20);

            Assert.AreEqual(anim.GetValue(SpriteAnimation.XProperty), anim.X, "XProperty and X should map to the same value");
            Assert.AreEqual(anim.GetValue(SpriteAnimation.YProperty), anim.Y, "YProperty and Y should map to the same value");

        }

        [TestMethod]
        public void SpriteAnimation_Should_Have_Fps_Property_Wihth_Default_Value()
        {

            SpriteAnimation anim = new SpriteAnimation();

            Assert.AreEqual(10, anim.Fps, "Default value for Fps is not correct");
            Assert.AreEqual(anim.GetValue(SpriteAnimation.FpsProperty), anim.Fps, "FpsProperty and Fps should map to the same value");

        }

        [TestMethod]
        public void SpriteAnimation_Should_Have_An_Animations_Property()
        {

            SpriteAnimation spriteAnim = new SpriteAnimation();

            FrameAnimation anim = new FrameAnimation()
            {
                Name = "name"
            };
            anim.Frames = new List<SpriteFrame> { new SpriteFrame(), new SpriteFrame() };
            spriteAnim.Animations = new List<FrameAnimation> { anim };

            Assert.AreSame(spriteAnim.Animations, spriteAnim.GetValue(SpriteAnimation.AnimationsProperty), "AnimationsProperty and Animations should return the same object");

            Assert.AreSame(anim, spriteAnim.Animations.First(), "Animations property does not return the correct animation");

            Assert.AreEqual(1, spriteAnim.Animations.Count(), "Animations property does not return the correct number of animations");

        }

        [TestMethod]
        public void SpriteAnimation_Should_Have_An_AnimatedSprite_Property()
        {

            SpriteAnimation spriteAnim = new SpriteAnimation();

            FrameAnimation anim = new FrameAnimation()
            {
                Name = "name"
            };
            anim.Frames = new List<SpriteFrame> { new SpriteFrame
            {
                Source = "/SilverTileTests;component/Tiles/0002.png"
            }};
            spriteAnim.Animations = new List<FrameAnimation> { anim };

            AnimatedSprite sprite = spriteAnim.GetAnimatedSprite<AnimatedSprite>();

            sprite.SetActiveAnimation("name");

            List<IFrame> frames = sprite.Animations["name"];
            Assert.AreEqual(frames.Count, sprite.Animations.Count, "Number of frames of animation is incorrect");
            Assert.AreSame(frames.First(), anim.Frames.First().Frame, "Animation frames are not the same");

        }

        [TestMethod]
        public void SpriteAnimations_GetAnimatedSprite_Should_Return_A_New_Object()
        {
            SpriteAnimation spriteAnim = new SpriteAnimation();

            FrameAnimation anim = new FrameAnimation()
            {
                Name = "name"
            };
            anim.Frames = new List<SpriteFrame> { new SpriteFrame
            {
                Source = "/SilverTileTests;component/Tiles/0002.png"
            }};
            spriteAnim.Animations = new List<FrameAnimation> { anim };

            AnimatedSprite sprite1 = spriteAnim.GetAnimatedSprite<AnimatedSprite>();
            AnimatedSprite sprite2 = spriteAnim.GetAnimatedSprite<AnimatedSprite>();

            Assert.AreNotSame(sprite1, sprite2, "Sprite1 and 2 should not reference the same object");

            List<IFrame> sprite1Anim = sprite1.Animations["name"];
            List<IFrame> sprite2Anim = sprite2.Animations["name"];

            Assert.AreSame(sprite1Anim[0], sprite2Anim[0], "Animations should reference the same frame objects");

        }

        [TestMethod]
        public void SpriteAnimations_GetAnimatedSprite_Should_Have_NonGeneric_Version()
        {

            SpriteAnimation spriteAnim = new SpriteAnimation();

            FrameAnimation anim = new FrameAnimation()
            {
                Name = "name"
            };
            anim.Frames = new List<SpriteFrame> { new SpriteFrame
            {
                Source = "/SilverTileTests;component/Tiles/0002.png"
            }};
            spriteAnim.Animations = new List<FrameAnimation> { anim };

            var sprite = spriteAnim.GetAnimatedSprite(typeof(AnimatedSprite));

            Assert.IsInstanceOfType(sprite, typeof(AnimatedSprite), "Sprite returned was not AnimatedSprite");

        }

        [TestMethod]
        public void SpriteAnimation_Xaml_Fragment_Should_Be_Parseable()
        {

            UserControl xamlUc = (UserControl)XamlReader.Load(_xaml);

            Assert.IsNotNull(xamlUc, "Xaml was not deserialized properly");

            object spriteAnimResource = xamlUc.Resources["Player"];
            Assert.IsNotNull(spriteAnimResource, "Player resource was not defined");
            Assert.IsInstanceOfType(spriteAnimResource, typeof(SpriteAnimation), "Player definintion was deserialized to the wrong type");

        }

        [TestMethod]
        public void SpriteAnimation_From_Xaml_Should_Be_Set_Up_Correctly()
        {

            UserControl xamlUc = (UserControl)XamlReader.Load(_xaml);
            SpriteAnimation spriteAnimResource = (SpriteAnimation)xamlUc.Resources["Player"];

            AnimatedSprite sprite = spriteAnimResource.GetAnimatedSprite<AnimatedSprite>();

            Assert.AreEqual(1, sprite.Animations.Count, "Sprite animations was not setup correctly");
            Assert.AreEqual(2, sprite.Animations["Left"].Count, "Animation count is not correct");
            Assert.AreEqual(20, sprite.Fps, "Fps was not set correctly");

        }

    }
}